package br.cnpq.webflowah.adaptation;

import java.io.PrintWriter;
import java.io.Writer;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

import org.mindswap.exceptions.ExecutionException;
import org.mindswap.owl.OWLIndividual;
import org.mindswap.owl.OWLValue;
import org.mindswap.owls.process.Input;
import org.mindswap.owls.process.Output;
import org.mindswap.owls.process.Process;
import org.mindswap.owls.process.execution.ProcessMonitor;
import org.mindswap.query.ValueMap;

public class ExecutionProcessMonitor implements ProcessMonitor {

	private PrintWriter out;
	private int monitorFilter;
	// TODO: usar um Map concorrente
	private Map<String, ValueMap> executionsOutputs;
	private String atualProcess;

	public String getAtualProcessURI() {
		return atualProcess;
	}

	public ExecutionProcessMonitor() {
		this(new PrintWriter(System.out));
	}

	public ExecutionProcessMonitor(PrintWriter printWriter) {
		this.monitorFilter = Process.ANY;
		this.setWriter(printWriter);
		this.executionsOutputs = new HashMap<String, ValueMap>();
	}

	public void setWriter(Writer writer) {
		this.out = (writer instanceof PrintWriter) ? (PrintWriter) writer
				: new PrintWriter(writer);
	}

	@Override
	public void executionStarted() {
		out.println("MyMonitor - All Execution Started");
		// TODO: Obter a quantidade de process:Perform
		// out.println("MyMonitor - There are " + executionsOutputs.size()
		// + " process to be executed");
		out.flush();
	}

	@Override
	public void executionFinished() {
		out.println("MyMonitor - All Execution Finished");
		out.flush();
	}

	@Override
	public void executionStarted(Process process, ValueMap inputs) {
		out.println("MyMonitor - Start executing process " + process);
		out.println("MyMonitor - Inputs:");
		for (Iterator i = process.getInputs().iterator(); i.hasNext();) {
			Input input = (Input) i.next();
			out.print("\t" + input.toPrettyString().trim() + " =  ");
			OWLValue value = inputs.getValue(input);
			if (value == null)
				value = input.getConstantValue();
			if (value == null)
				out.println("<< NO VALUE >>");
			else if (value.isDataValue())
				out.println(value.toString().trim());
			else {
				OWLIndividual ind = (OWLIndividual) value;
				if (ind.isAnon())
					out.println(ind.toRDF(false).trim());
				else
					out.println(value.toString().trim());
			}
		}
		atualProcess = process.getURI().toString();
		out.println();
		out.flush();
	}

	@Override
	public void executionFinished(Process process, ValueMap inputs,
			ValueMap outputs) {
		out.println("MyMonitor - Execution finished for " + process);
		out.println("MyMonitor - Outputs:");
		for (Iterator i = process.getOutputs().iterator(); i.hasNext();) {
			Output output = (Output) i.next();
			out.print("\t" + output.toPrettyString().trim() + " =  ");
			OWLValue value = outputs.getValue(output);
			if (value == null)
				out.println("<< NO VALUE >>");
			else if (value.isDataValue())
				out.print(value.toString().trim());
			else {
				OWLIndividual ind = (OWLIndividual) value;
				if (ind.isAnon())
					out.println(ind.toRDF(false).trim());
				else
					out.println(value.toString().trim());
			}
		}
		this.executionsOutputs.put(process.getName(), outputs);
		out.println();
		out.flush();
	}

	@Override
	public void executionFailed(ExecutionException e) {
		out.println("MyMonitor - Execution failed: ");
		out.println(e.toString());
		out.flush();
	}

	public void executionFailed(ExecutionException e, ValueMap inputs,
			ValueMap outputs) {
		out.println("MyMonitor - Execution Failed\n\tProcess: " + atualProcess);
		out.println(e.toString());
		out.flush();
	}

	@Override
	public void setMonitorFilter(int processType) {
		this.monitorFilter = processType;

	}

	@Override
	public int getMonitorFilter() {
		return this.monitorFilter;
	}

	/**
	 * Return all generated outputs
	 * 
	 * @return
	 */
	public Map<String, ValueMap> getAllExecutionsOutputs() {
		return this.executionsOutputs;
	}

	public ValueMap getMergedValueMap() {
		ValueMap values = new ValueMap(), aux = null;
		Iterator<ValueMap> i = executionsOutputs.values().iterator();
		out.println("MyMonitor - Return Merged ValueMaps");
		out.println("MyMonitor - Values:");
		while (i.hasNext()) {
			aux = i.next();
			out.println("\t" + aux);
			values.addMap(aux);
		}
		return values;
	}
}
